{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Requirement already satisfied: torch==2.2 in /opt/conda/lib/python3.10/site-packages (2.2.0)\n",
      "Requirement already satisfied: filelock in /opt/conda/lib/python3.10/site-packages (from torch==2.2) (3.13.1)\n",
      "Requirement already satisfied: typing-extensions>=4.8.0 in /opt/conda/lib/python3.10/site-packages (from torch==2.2) (4.9.0)\n",
      "Requirement already satisfied: sympy in /opt/conda/lib/python3.10/site-packages (from torch==2.2) (1.12)\n",
      "Requirement already satisfied: networkx in /opt/conda/lib/python3.10/site-packages (from torch==2.2) (2.8.5)\n",
      "Requirement already satisfied: jinja2 in /opt/conda/lib/python3.10/site-packages (from torch==2.2) (3.1.2)\n",
      "Requirement already satisfied: fsspec in /opt/conda/lib/python3.10/site-packages (from torch==2.2) (2023.12.2)\n",
      "Requirement already satisfied: nvidia-cuda-nvrtc-cu12==12.1.105 in /opt/conda/lib/python3.10/site-packages (from torch==2.2) (12.1.105)\n",
      "Requirement already satisfied: nvidia-cuda-runtime-cu12==12.1.105 in /opt/conda/lib/python3.10/site-packages (from torch==2.2) (12.1.105)\n",
      "Requirement already satisfied: nvidia-cuda-cupti-cu12==12.1.105 in /opt/conda/lib/python3.10/site-packages (from torch==2.2) (12.1.105)\n",
      "Requirement already satisfied: nvidia-cudnn-cu12==8.9.2.26 in /opt/conda/lib/python3.10/site-packages (from torch==2.2) (8.9.2.26)\n",
      "Requirement already satisfied: nvidia-cublas-cu12==12.1.3.1 in /opt/conda/lib/python3.10/site-packages (from torch==2.2) (12.1.3.1)\n",
      "Requirement already satisfied: nvidia-cufft-cu12==11.0.2.54 in /opt/conda/lib/python3.10/site-packages (from torch==2.2) (11.0.2.54)\n",
      "Requirement already satisfied: nvidia-curand-cu12==10.3.2.106 in /opt/conda/lib/python3.10/site-packages (from torch==2.2) (10.3.2.106)\n",
      "Requirement already satisfied: nvidia-cusolver-cu12==11.4.5.107 in /opt/conda/lib/python3.10/site-packages (from torch==2.2) (11.4.5.107)\n",
      "Requirement already satisfied: nvidia-cusparse-cu12==12.1.0.106 in /opt/conda/lib/python3.10/site-packages (from torch==2.2) (12.1.0.106)\n",
      "Requirement already satisfied: nvidia-nccl-cu12==2.19.3 in /opt/conda/lib/python3.10/site-packages (from torch==2.2) (2.19.3)\n",
      "Requirement already satisfied: nvidia-nvtx-cu12==12.1.105 in /opt/conda/lib/python3.10/site-packages (from torch==2.2) (12.1.105)\n",
      "Requirement already satisfied: triton==2.2.0 in /opt/conda/lib/python3.10/site-packages (from torch==2.2) (2.2.0)\n",
      "Requirement already satisfied: nvidia-nvjitlink-cu12 in /opt/conda/lib/python3.10/site-packages (from nvidia-cusolver-cu12==11.4.5.107->torch==2.2) (12.3.101)\n",
      "Requirement already satisfied: MarkupSafe>=2.0 in /opt/conda/lib/python3.10/site-packages (from jinja2->torch==2.2) (2.1.3)\n",
      "Requirement already satisfied: mpmath>=0.19 in /opt/conda/lib/python3.10/site-packages (from sympy->torch==2.2) (1.3.0)\n",
      "Requirement already satisfied: torchvision==0.17 in /opt/conda/lib/python3.10/site-packages (0.17.0)\n",
      "Requirement already satisfied: numpy in /opt/conda/lib/python3.10/site-packages (from torchvision==0.17) (1.26.2)\n",
      "Requirement already satisfied: requests in /opt/conda/lib/python3.10/site-packages (from torchvision==0.17) (2.28.1)\n",
      "Requirement already satisfied: torch==2.2.0 in /opt/conda/lib/python3.10/site-packages (from torchvision==0.17) (2.2.0)\n",
      "Requirement already satisfied: pillow!=8.3.*,>=5.3.0 in /opt/conda/lib/python3.10/site-packages (from torchvision==0.17) (9.3.0)\n",
      "Requirement already satisfied: filelock in /opt/conda/lib/python3.10/site-packages (from torch==2.2.0->torchvision==0.17) (3.13.1)\n",
      "Requirement already satisfied: typing-extensions>=4.8.0 in /opt/conda/lib/python3.10/site-packages (from torch==2.2.0->torchvision==0.17) (4.9.0)\n",
      "Requirement already satisfied: sympy in /opt/conda/lib/python3.10/site-packages (from torch==2.2.0->torchvision==0.17) (1.12)\n",
      "Requirement already satisfied: networkx in /opt/conda/lib/python3.10/site-packages (from torch==2.2.0->torchvision==0.17) (2.8.5)\n",
      "Requirement already satisfied: jinja2 in /opt/conda/lib/python3.10/site-packages (from torch==2.2.0->torchvision==0.17) (3.1.2)\n",
      "Requirement already satisfied: fsspec in /opt/conda/lib/python3.10/site-packages (from torch==2.2.0->torchvision==0.17) (2023.12.2)\n",
      "Requirement already satisfied: nvidia-cuda-nvrtc-cu12==12.1.105 in /opt/conda/lib/python3.10/site-packages (from torch==2.2.0->torchvision==0.17) (12.1.105)\n",
      "Requirement already satisfied: nvidia-cuda-runtime-cu12==12.1.105 in /opt/conda/lib/python3.10/site-packages (from torch==2.2.0->torchvision==0.17) (12.1.105)\n",
      "Requirement already satisfied: nvidia-cuda-cupti-cu12==12.1.105 in /opt/conda/lib/python3.10/site-packages (from torch==2.2.0->torchvision==0.17) (12.1.105)\n",
      "Requirement already satisfied: nvidia-cudnn-cu12==8.9.2.26 in /opt/conda/lib/python3.10/site-packages (from torch==2.2.0->torchvision==0.17) (8.9.2.26)\n",
      "Requirement already satisfied: nvidia-cublas-cu12==12.1.3.1 in /opt/conda/lib/python3.10/site-packages (from torch==2.2.0->torchvision==0.17) (12.1.3.1)\n",
      "Requirement already satisfied: nvidia-cufft-cu12==11.0.2.54 in /opt/conda/lib/python3.10/site-packages (from torch==2.2.0->torchvision==0.17) (11.0.2.54)\n",
      "Requirement already satisfied: nvidia-curand-cu12==10.3.2.106 in /opt/conda/lib/python3.10/site-packages (from torch==2.2.0->torchvision==0.17) (10.3.2.106)\n",
      "Requirement already satisfied: nvidia-cusolver-cu12==11.4.5.107 in /opt/conda/lib/python3.10/site-packages (from torch==2.2.0->torchvision==0.17) (11.4.5.107)\n",
      "Requirement already satisfied: nvidia-cusparse-cu12==12.1.0.106 in /opt/conda/lib/python3.10/site-packages (from torch==2.2.0->torchvision==0.17) (12.1.0.106)\n",
      "Requirement already satisfied: nvidia-nccl-cu12==2.19.3 in /opt/conda/lib/python3.10/site-packages (from torch==2.2.0->torchvision==0.17) (2.19.3)\n",
      "Requirement already satisfied: nvidia-nvtx-cu12==12.1.105 in /opt/conda/lib/python3.10/site-packages (from torch==2.2.0->torchvision==0.17) (12.1.105)\n",
      "Requirement already satisfied: triton==2.2.0 in /opt/conda/lib/python3.10/site-packages (from torch==2.2.0->torchvision==0.17) (2.2.0)\n",
      "Requirement already satisfied: nvidia-nvjitlink-cu12 in /opt/conda/lib/python3.10/site-packages (from nvidia-cusolver-cu12==11.4.5.107->torch==2.2.0->torchvision==0.17) (12.3.101)\n",
      "Requirement already satisfied: charset-normalizer<3,>=2 in /opt/conda/lib/python3.10/site-packages (from requests->torchvision==0.17) (2.1.0)\n",
      "Requirement already satisfied: idna<4,>=2.5 in /opt/conda/lib/python3.10/site-packages (from requests->torchvision==0.17) (3.3)\n",
      "Requirement already satisfied: urllib3<1.27,>=1.21.1 in /opt/conda/lib/python3.10/site-packages (from requests->torchvision==0.17) (1.26.10)\n",
      "Requirement already satisfied: certifi>=2017.4.17 in /opt/conda/lib/python3.10/site-packages (from requests->torchvision==0.17) (2022.6.15)\n",
      "Requirement already satisfied: MarkupSafe>=2.0 in /opt/conda/lib/python3.10/site-packages (from jinja2->torch==2.2.0->torchvision==0.17) (2.1.3)\n",
      "Requirement already satisfied: mpmath>=0.19 in /opt/conda/lib/python3.10/site-packages (from sympy->torch==2.2.0->torchvision==0.17) (1.3.0)\n",
      "Requirement already satisfied: matplotlib==3.5.2 in /opt/conda/lib/python3.10/site-packages (3.5.2)\n",
      "Requirement already satisfied: cycler>=0.10 in /opt/conda/lib/python3.10/site-packages (from matplotlib==3.5.2) (0.12.1)\n",
      "Requirement already satisfied: fonttools>=4.22.0 in /opt/conda/lib/python3.10/site-packages (from matplotlib==3.5.2) (4.46.0)\n",
      "Requirement already satisfied: kiwisolver>=1.0.1 in /opt/conda/lib/python3.10/site-packages (from matplotlib==3.5.2) (1.4.5)\n",
      "Requirement already satisfied: numpy>=1.17 in /opt/conda/lib/python3.10/site-packages (from matplotlib==3.5.2) (1.26.2)\n",
      "Requirement already satisfied: packaging>=20.0 in /opt/conda/lib/python3.10/site-packages (from matplotlib==3.5.2) (21.3)\n",
      "Requirement already satisfied: pillow>=6.2.0 in /opt/conda/lib/python3.10/site-packages (from matplotlib==3.5.2) (9.3.0)\n",
      "Requirement already satisfied: pyparsing>=2.2.1 in /opt/conda/lib/python3.10/site-packages (from matplotlib==3.5.2) (3.0.9)\n",
      "Requirement already satisfied: python-dateutil>=2.7 in /opt/conda/lib/python3.10/site-packages (from matplotlib==3.5.2) (2.8.2)\n",
      "Requirement already satisfied: six>=1.5 in /opt/conda/lib/python3.10/site-packages (from python-dateutil>=2.7->matplotlib==3.5.2) (1.16.0)\n",
      "Collecting poutyne==1.12.0\n",
      "  Downloading Poutyne-1.12-py3-none-any.whl (211 kB)\n",
      "\u001b[2K     \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m211.2/211.2 kB\u001b[0m \u001b[31m12.7 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
      "\u001b[?25hRequirement already satisfied: numpy in /opt/conda/lib/python3.10/site-packages (from poutyne==1.12.0) (1.26.2)\n",
      "Requirement already satisfied: torch in /opt/conda/lib/python3.10/site-packages (from poutyne==1.12.0) (2.2.0)\n",
      "Requirement already satisfied: torchmetrics in /opt/conda/lib/python3.10/site-packages (from poutyne==1.12.0) (1.2.1)\n",
      "Requirement already satisfied: filelock in /opt/conda/lib/python3.10/site-packages (from torch->poutyne==1.12.0) (3.13.1)\n",
      "Requirement already satisfied: typing-extensions>=4.8.0 in /opt/conda/lib/python3.10/site-packages (from torch->poutyne==1.12.0) (4.9.0)\n",
      "Requirement already satisfied: sympy in /opt/conda/lib/python3.10/site-packages (from torch->poutyne==1.12.0) (1.12)\n",
      "Requirement already satisfied: networkx in /opt/conda/lib/python3.10/site-packages (from torch->poutyne==1.12.0) (2.8.5)\n",
      "Requirement already satisfied: jinja2 in /opt/conda/lib/python3.10/site-packages (from torch->poutyne==1.12.0) (3.1.2)\n",
      "Requirement already satisfied: fsspec in /opt/conda/lib/python3.10/site-packages (from torch->poutyne==1.12.0) (2023.12.2)\n",
      "Requirement already satisfied: nvidia-cuda-nvrtc-cu12==12.1.105 in /opt/conda/lib/python3.10/site-packages (from torch->poutyne==1.12.0) (12.1.105)\n",
      "Requirement already satisfied: nvidia-cuda-runtime-cu12==12.1.105 in /opt/conda/lib/python3.10/site-packages (from torch->poutyne==1.12.0) (12.1.105)\n",
      "Requirement already satisfied: nvidia-cuda-cupti-cu12==12.1.105 in /opt/conda/lib/python3.10/site-packages (from torch->poutyne==1.12.0) (12.1.105)\n",
      "Requirement already satisfied: nvidia-cudnn-cu12==8.9.2.26 in /opt/conda/lib/python3.10/site-packages (from torch->poutyne==1.12.0) (8.9.2.26)\n",
      "Requirement already satisfied: nvidia-cublas-cu12==12.1.3.1 in /opt/conda/lib/python3.10/site-packages (from torch->poutyne==1.12.0) (12.1.3.1)\n",
      "Requirement already satisfied: nvidia-cufft-cu12==11.0.2.54 in /opt/conda/lib/python3.10/site-packages (from torch->poutyne==1.12.0) (11.0.2.54)\n",
      "Requirement already satisfied: nvidia-curand-cu12==10.3.2.106 in /opt/conda/lib/python3.10/site-packages (from torch->poutyne==1.12.0) (10.3.2.106)\n",
      "Requirement already satisfied: nvidia-cusolver-cu12==11.4.5.107 in /opt/conda/lib/python3.10/site-packages (from torch->poutyne==1.12.0) (11.4.5.107)\n",
      "Requirement already satisfied: nvidia-cusparse-cu12==12.1.0.106 in /opt/conda/lib/python3.10/site-packages (from torch->poutyne==1.12.0) (12.1.0.106)\n",
      "Requirement already satisfied: nvidia-nccl-cu12==2.19.3 in /opt/conda/lib/python3.10/site-packages (from torch->poutyne==1.12.0) (2.19.3)\n",
      "Requirement already satisfied: nvidia-nvtx-cu12==12.1.105 in /opt/conda/lib/python3.10/site-packages (from torch->poutyne==1.12.0) (12.1.105)\n",
      "Requirement already satisfied: triton==2.2.0 in /opt/conda/lib/python3.10/site-packages (from torch->poutyne==1.12.0) (2.2.0)\n",
      "Requirement already satisfied: nvidia-nvjitlink-cu12 in /opt/conda/lib/python3.10/site-packages (from nvidia-cusolver-cu12==11.4.5.107->torch->poutyne==1.12.0) (12.3.101)\n",
      "Requirement already satisfied: packaging>17.1 in /opt/conda/lib/python3.10/site-packages (from torchmetrics->poutyne==1.12.0) (21.3)\n",
      "Requirement already satisfied: lightning-utilities>=0.8.0 in /opt/conda/lib/python3.10/site-packages (from torchmetrics->poutyne==1.12.0) (0.10.0)\n",
      "Requirement already satisfied: setuptools in /opt/conda/lib/python3.10/site-packages (from lightning-utilities>=0.8.0->torchmetrics->poutyne==1.12.0) (68.2.2)\n",
      "Requirement already satisfied: pyparsing!=3.0.5,>=2.0.2 in /opt/conda/lib/python3.10/site-packages (from packaging>17.1->torchmetrics->poutyne==1.12.0) (3.0.9)\n",
      "Requirement already satisfied: MarkupSafe>=2.0 in /opt/conda/lib/python3.10/site-packages (from jinja2->torch->poutyne==1.12.0) (2.1.3)\n",
      "Requirement already satisfied: mpmath>=0.19 in /opt/conda/lib/python3.10/site-packages (from sympy->torch->poutyne==1.12.0) (1.3.0)\n",
      "Installing collected packages: poutyne\n",
      "Successfully installed poutyne-1.12\n"
     ]
    }
   ],
   "source": [
    "!pip install torch==2.2\n",
    "!pip install torchvision==0.17\n",
    "!pip install matplotlib==3.5.2\n",
    "!pip install poutyne==1.12.0"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "/opt/conda/lib/python3.10/site-packages/transformers/utils/generic.py:441: UserWarning: torch.utils._pytree._register_pytree_node is deprecated. Please use torch.utils._pytree.register_pytree_node instead.\n",
      "  _torch_pytree._register_pytree_node(\n",
      "2024-02-16 02:04:56.133404: E external/local_xla/xla/stream_executor/cuda/cuda_dnn.cc:9261] Unable to register cuDNN factory: Attempting to register factory for plugin cuDNN when one has already been registered\n",
      "2024-02-16 02:04:56.133460: E external/local_xla/xla/stream_executor/cuda/cuda_fft.cc:607] Unable to register cuFFT factory: Attempting to register factory for plugin cuFFT when one has already been registered\n",
      "2024-02-16 02:04:56.135131: E external/local_xla/xla/stream_executor/cuda/cuda_blas.cc:1515] Unable to register cuBLAS factory: Attempting to register factory for plugin cuBLAS when one has already been registered\n"
     ]
    }
   ],
   "source": [
    "import math\n",
    "\n",
    "import matplotlib.pyplot as plt\n",
    "import numpy as np\n",
    "import torch\n",
    "import torch.nn as nn\n",
    "import torch.optim as optim\n",
    "from torch.utils.data import Subset, DataLoader\n",
    "from torchvision import transforms, utils\n",
    "from torchvision.datasets.mnist import MNIST\n",
    "\n",
    "from poutyne import set_seeds, Model"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [],
   "source": [
    "set_seeds(42)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [],
   "source": [
    "cuda_device = 0\n",
    "device = torch.device(\"cuda:%d\" % cuda_device if torch.cuda.is_available() else \"cpu\")\n",
    "\n",
    "train_split_percent = 0.8\n",
    "\n",
    "num_classes = 10\n",
    "\n",
    "batch_size = 32\n",
    "learning_rate = 0.1\n",
    "num_epochs = 1"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Downloading http://yann.lecun.com/exdb/mnist/train-images-idx3-ubyte.gz\n",
      "Downloading http://yann.lecun.com/exdb/mnist/train-images-idx3-ubyte.gz to ./mnist/MNIST/raw/train-images-idx3-ubyte.gz\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "100%|██████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 9912422/9912422 [00:00<00:00, 257662891.88it/s]"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Extracting ./mnist/MNIST/raw/train-images-idx3-ubyte.gz to ./mnist/MNIST/raw\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "Downloading http://yann.lecun.com/exdb/mnist/train-labels-idx1-ubyte.gz\n",
      "Downloading http://yann.lecun.com/exdb/mnist/train-labels-idx1-ubyte.gz to ./mnist/MNIST/raw/train-labels-idx1-ubyte.gz\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "100%|███████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 28881/28881 [00:00<00:00, 98324426.81it/s]\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Extracting ./mnist/MNIST/raw/train-labels-idx1-ubyte.gz to ./mnist/MNIST/raw\n",
      "\n",
      "Downloading http://yann.lecun.com/exdb/mnist/t10k-images-idx3-ubyte.gz\n",
      "Downloading http://yann.lecun.com/exdb/mnist/t10k-images-idx3-ubyte.gz to ./mnist/MNIST/raw/t10k-images-idx3-ubyte.gz\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "100%|███████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 1648877/1648877 [00:00<00:00, 70367117.37it/s]\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Extracting ./mnist/MNIST/raw/t10k-images-idx3-ubyte.gz to ./mnist/MNIST/raw\n",
      "\n",
      "Downloading http://yann.lecun.com/exdb/mnist/t10k-labels-idx1-ubyte.gz\n",
      "Downloading http://yann.lecun.com/exdb/mnist/t10k-labels-idx1-ubyte.gz to ./mnist/MNIST/raw/t10k-labels-idx1-ubyte.gz\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "100%|██████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 4542/4542 [00:00<00:00, 9675230.46it/s]"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Extracting ./mnist/MNIST/raw/t10k-labels-idx1-ubyte.gz to ./mnist/MNIST/raw\n",
      "\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\n"
     ]
    }
   ],
   "source": [
    "full_train_dataset = MNIST('./mnist/', train=True, download=True, transform=transforms.ToTensor())\n",
    "test_dataset = MNIST('./mnist/', train=False, download=True, transform=transforms.ToTensor())\n",
    "\n",
    "num_data = len(full_train_dataset)\n",
    "indices = list(range(num_data))\n",
    "np.random.shuffle(indices)\n",
    "\n",
    "split = math.floor(train_split_percent * num_data)\n",
    "\n",
    "train_indices = indices[:split]\n",
    "train_dataset = Subset(full_train_dataset, train_indices)\n",
    "\n",
    "valid_indices = indices[split:]\n",
    "valid_dataset = Subset(full_train_dataset, valid_indices)\n",
    "\n",
    "train_loader = DataLoader(train_dataset, batch_size=batch_size, num_workers=2, shuffle=True)\n",
    "valid_loader = DataLoader(valid_dataset, batch_size=batch_size, num_workers=2)\n",
    "test_loader = DataLoader(test_dataset, batch_size=batch_size, num_workers=2)\n",
    "\n",
    "loaders = train_loader, valid_loader, test_loader"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "iVBORw0KGgoAAAANSUhEUgAAAz8AAAG2CAYAAABRdTh6AAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjUuMiwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8qNh9FAAAACXBIWXMAAA9hAAAPYQGoP6dpAABsf0lEQVR4nO3deZyN9fvH8Wvs64zGMoOQpOwUpWlTEUlSaZOypEhUqESFkiVKi/KztKDSQqVQlBBZsqYsJUrWhpAZZBnm/P7o6+q6784ZZ8w5c+bM/Xo+HufxeN9z7vucj5kz58zHfd3XJ8bn8/kEAAAAAHK5PJEeAAAAAABkByY/AAAAADyByQ8AAAAAT2DyAwAAAMATmPwAAAAA8AQmPwAAAAA8gckPAAAAAE9g8gMAAADAE5j8AAAAAPAEJj8AAAAAPCGik59Ro0bJWWedJYUKFZKGDRvKsmXLIjkcAAAAALlYxCY/H374ofTq1UsGDBggq1atkrp160qzZs1k9+7dkRoSAAAAgFwsxufz+SLxxA0bNpQLL7xQXnvtNRERSU9PlwoVKsiDDz4offr0yfDY9PR02blzpxQvXlxiYmKyY7gAAAAAciCfzycHDhyQcuXKSZ48GZ/byZdNY3I4duyYrFy5Uvr27atfy5MnjzRp0kSWLFnyn/2PHj0qR48e1e0dO3ZIjRo1smWsAAAAAHK+bdu2yZlnnpnhPhEpe9uzZ4+cOHFCEhISHF9PSEiQ5OTk/+w/dOhQiYuL0xsTHwAAAABW8eLFT7lPVHR769u3r6SkpOht27ZtkR4SAAAAgBwkmMthIlL2VqpUKcmbN6/s2rXL8fVdu3ZJYmLif/YvWLCgFCxYMLuGBwAAACAXisiZnwIFCkj9+vVlzpw5+rX09HSZM2eOJCUlRWJIAAAAAHK5iJz5ERHp1auXtG/fXho0aCAXXXSRvPzyy3Lo0CHp2LFjpIYEAAAAIBeL2OTn9ttvlz///FP69+8vycnJUq9ePZk1a9Z/miAAAAAAQChEbJ2frEhNTZW4uLhIDwMAAABADpGSkiKxsbEZ7hMV3d4AAAAAIKuY/AAAAADwBCY/AAAAADyByQ8AAAAAT2DyAwAAAMATmPwAAAAA8AQmPwAAAAA8IWKLnAKhUr58ec0vvPCC477bbrvN7zFz5szRPGPGDMd9o0eP1pyWlhaKIXrW008/rblRo0aa58+fH9QxAAAAocSZHwAAAACewOQHAAAAgCfE+Hw+X6QHkVmpqakSFxcX6WEEJW/evJp79uyp+cknn9T86KOPan7zzTezZ2BRzpa6Pffcc5rbtGmT5cd+8cUXNffu3TvLj5fbXXnllY7tAQMGBLwvs5555hnNlMOFTseOHTWfeeaZjvvuvvtuzVWrVtU8atQozd27dw/j6AAAOD0pKSkSGxub4T6c+QEAAADgCUx+AAAAAHgCZW9hNm3aNM3XX3+9333eeustzd9++63jvnfeeUdzenp6iEcXvebOnav5oosu0jxp0iTHfpMnT9a8a9cuzbfccovmp556KuDz1KtXT/PatWtPa6y5nbsczZa92bK1QOz+wbrqqqs0f/PNN5k+3osWL16s2f7OxMTEBHW8/agYO3as5m7duoVgdDnT+++/r/m3337TbEsARUR27twZ9rHYz7yUlJSwP19ukz9/fs01atRw3PfQQw9pvvXWWzUXL17c72OdOHHCsf38889rtp8n7v28pkKFCprPPvtszXfeeadjv7p162oO5r3J/WfrvHnzNN90002aU1NTMzni6GRfpxUrVtTcpUuXgMdceOGFmi+++GK/+9jvs/tnsX79es0ff/yx5v79+wcx4vCi7A0AAAAA/ofJDwAAAABPYPIDAAAAwBO45icE7FhsXb2ISLVq1TQHW1tvHT582O/XX3nlFc2vvfaa5uyoPc8JChcurNl+X//++++gjs+T5995/8CBAx339enTR/PevXs1N2rUSPPPP/8c/GA9xtZf22tzgmXbY9vHsux1PqfzHLnZzTffrHn8+PGaixQpotm+/t2WLFmiOSkpye8+9mPDts0WcV6nGO1++OEHzTVr1tTs/v2/9NJLNYfyepxatWpptt/XpUuXOvZ7/PHHw/L80e6GG27QPGTIEM3ua35Cady4cZrvv//+sD1PdihTpozmzp07a87o/eOuu+7SHB8f7zeHk12qwi4jkpv16tVLs73+LLvs2LFDs73mKFK45gcAAAAA/ofJDwAAAABPyBfpAeQGTzzxhObq1asH3G/Pnj2aCxYsqDlQO00RZ3mXZUuz7r33Xs0tWrRw7Ld8+fKAjx3NApUDBsu2DR89erTjPvs9rFOnjubLL79cM2Vvgc2fPz9LxwcqabMlcLY0zmb38V6UN29ezcWKFfO7jy1TsGVyIiLr1q3TfN9992l+8MEHNdu2te7SuGgve7PteUuWLOl3n2PHjjm209LSwjKW8847T7Mtgatdu7ZjP1ve6C6J8wL7OWnfz20Jli3VOn78uOP4L7/8UrN9/duvly9fXvPEiRMdx9vSa7uMwvDhwzXbVuk5WdGiRTXPmTNHsy37DLXPP/9c819//eV3n3PPPVezbYftdv7554duYFGiefPmp9zHfYXLoUOHNNtSTev111/X7H4vtO9511xzTVDjzEk48wMAAADAE5j8AAAAAPAEyt5Ok+0ik1FHkYMHD2q2ZSNfffWVZlum4nbGGWdofvLJJzXbUpVSpUppnjp1quP4qlWras5qqVhuZUuAREQmTJig2XaOsSt/29PBcHr66adD9ljBlLBR9hacadOmaV60aJHmFStWBDzm3Xff1WxLiKy2bds6tu3vz7JlyzI7zIjbtm2bZtvtMTExUbN9zxVxloQE23EyGPb9P6NuofXq1dPsxbI328mtXbt2fvexZWfuz+xPP/30lM/RsmVLzRn9LGxXM1seZ8umczI7/tMpdbN/89iy+w8++ECzfV8RETly5IhmW55lS9hmzpwZ1PO7O+56gS31vPrqq/3u061bN8f22LFjQ/b8GX2G5FSc+QEAAADgCUx+AAAAAHgCZW+nyZa92VPg7tPh9lT56XTBsh3iOnTo4Pexhg0bprlcuXKO40eOHKnZdm5C5tnyRNs5yHaOQ2gFWuTUCmWZXW7wxRdfaK5SpYrmP/74Q/PRo0eDeizb+bB+/fp+90lNTXVsR2OpWyCrV6/WbEuA3O+z99xzj+Znnnkm7ONysyV5XnDHHXc4tt0lPSf99NNPmu1n8el0Xlu/fr3mXbt2Oe7bvHmz5osvvljzhRdeqNl2hbVlejlNcnKyZtuF7YILLtC8Zs0axzH2b5Bff/1V89atW4N6Tvt52qZNG80vvPCCZrvgqtvKlSs15+TvbbjceOONp9xn7dq14R9IFOHMDwAAAABPYPIDAAAAwBMoe8sE2wWlUaNGfvdxl+nYrkqhZBe1a9WqlWZbjifi7IRlOwcFWkgMIl9//bXfr9ufeY0aNTRzOjlr3N3agil1i0RpUbSwi9fZHKwrrrhCs+1QGUhufv3bLmoZsV01IyHSz58d7ILTtguniEi+fP/+KWPfv205UFa78NlyLrvgpojz9+y6667TbDss2q6II0aMcBwfbBlqdrCLV9pSwVCyJXQiIo8//rhm21U1kClTpji2bYe/nPS9DKfSpUtrdi807Y+7K2cw3Qft4qfu8mb3QsHRhjM/AAAAADyByQ8AAAAAT2DyAwAAAMATuOYnE2x7TdtC1nK30MyOukh7/Y/7mh87TrsKOdf8BHbeeef5/fr333+v+ffff8+m0UQfew2P+3qekwYMGJDpx7XX+dDeOnz69u2rOVB76x07dmi+8847wz6mSLEr1Ge02r29TgKhY5eO6Nevn2Z3a+/du3dr7tGjh+asXucTyIEDBwLe980332i2LbCrV6+uedSoUY5j7DIUPp8vBCPMea655hrNn376qeO+woUL+z3m8OHDmj/44APNnTt3dux34sSJEIwwutj33bPPPvuU+3fp0iXTzzF48GDN77//vuO+J598UvOWLVsy/diRxpkfAAAAAJ7A5AcAAACAJ1D2lgmBSt0s2w4T0aFJkyaO7fvvv9/vfrZU8ODBg2EdUzRxl6CdTklbILaEhFK3zLvssss0FytWTLMts6lQoYLjmEBtk1evXq35hx9+0JybS2jfeOMNzXfddZdmd5mbu/UyQuOmm27S3Lp164D7DRo0SPP69evDOqZTsZ8N9vfsyy+/1HzPPfc4jnnppZc0r1u3Loyjy162nM3+GwOVubmlpKRoXrNmjWa7bIeIyL59+zSnp6dnepzRIE8e57mKFi1aZOnx7HvY1KlTNdu/h+zyLm3atHEcX7ZsWc3NmjXTHC0tsDnzAwAAAMATmPwAAAAA8ATK3kIsN52y9oolS5Y4tm23N3uq+dtvv822MeEfgbrFIbCrr75a82effaa5SJEimX4sW8bbtGlTzXv37j3N0UWXrVu3arYdpdxlbxdffLFm+z276KKLNNsSzlCzP/MSJUpo3r9/f9ieMztccsklfr9uS8hEnOWJOcncuXM1f/3115ptmZCIyKWXXqo5N/0NkT9/fs3uUrVg2K5+trTUXWb60Ucfae7atavm3PQ+lS+f88/1yy+/3O9+tuzy5Zdf1vzxxx879tu5c6fmPXv2aLY/p169eml+7LHHHMfbz+a33npLc7t27fyOK6fhzA8AAAAAT2DyAwAAAMATKHuDZ9jTxAUKFNDs7u5Wvnx5zbZzjM22c5bXO78F24UtUNnPvHnzgjreLv7HgqfZzy446RW2NMSWvcXGxjr2Gz16tGa7+F9CQoJmuzCs26uvvur36w0bNgxqnLa8LVq6LQViS42TkpL87rN48WLH9pEjR8I6plCwC5662TK4cePGZcdwskVqaqrmoUOHai5YsKBjv+bNm2u+4IILNNsSzozccsstmitXrqzZfl9tR7hodOzYMce27X5oFwC25WkLFy7M9PPY7p32cd3ved27d9d88803ax45cqTmFStWZPr5swtnfgAAAAB4ApMfAAAAAJ4Q47O1JFEiNTVV4uLisv15R4wYoblnz55+9+nYsaNje+LEiWEdk4hIhw4dNNuuG27nnnuu5k2bNoVzSBFTpkwZx/YjjzyiuUePHprz5s0b1OPZUh/7q2K7aH3yySeOYyZNmhTUY8M/W8YWzIKp7nK6q666KsQjil62i5Qt1bTc71m2VMSWOsyZM0ezXfAuN3VUysjjjz+ueciQISF9bFvqdTqLNE6fPl2zLYexpXrRwi66u2XLFr/73HrrrY5tdyernOiXX37RfM455zju69atm2ZbQulFtmzN/p13/fXXa7799tsdx9SsWdPvY02ePFnzHXfcEaoh5mi2K9xDDz2kefv27Y797PcmGMWLF3dsL1++XLNdGNt+Htv3ouzsPJmSkvKfMj03zvwAAAAA8AQmPwAAAAA8gckPAAAAAE/gmp9MCOaan5kzZzq2W7RoEZaxFC1aVPOiRYs016lTx7Hfhx9+qPmee+7RfPjw4bCMKxLstQwPPvig475nn31Ws/3ZLFu2THOnTp0cx5x55pmav/jiC80lS5bU3KBBA822Xl/E2dK0cePGmrdt25bBvwKnYlti29Wl3WzNMdf/ZN6jjz6qediwYX73sat4e+UaN9ue134WiDjb6NvrD37++WfNtm22W5EiRTRffPHFWRpn2bJlNf/5559ZeqxIsK+tCRMmaLbvq9WqVXMck5aWFvZxnQ47zh9//FGzvS5DRKRevXp+94N/toW8iMhPP/2k2bbH3r17t+ZatWpp3rNnT/gGFwH2val3796a7TXPLVu2dBzz7bffZuk5u3btqvm1117zu4/9e3TdunVZer7M4JofAAAAAPgfJj8AAAAAPCHfqXfBSbaNdKCyt+xiT23aU4uHDh1y7GfbBuemUjfr5Zdf1mzbfos421DbcgpbHmfL3NzsaskbNmzQbEuDbDtJEZGzzz7b7342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jD3t78WyN/s7MHv2bM32+2JLM9955x3H8fZ3ZunSpZqHDRum+eGHH9b85JNPOo73SnlJuNhue5YtIbrpppsc97nfg7zGlpTZ919b6ma7GrrLpPLnz+/3cW2HQ7uwb0Zst7ndu3dr7tixo2ZbtpuT2ffvBx98MKhjVq5cqXnfvn0hG4stAbXlVBmx719eWfzadjW86667Au43d+5czVkte7Od3OznT0xMjOadO3c6jrEdXyOBMz8AAAAAPIHJDwAAAABPYPIDAAAAwBO45idC7PULN954o2a7oroIbZODYeuy3StP16tX75TH23bKp6Nq1aqO7QULFmhu1qyZ5tWrV2fpeXKq2NhYx7atDbftrUNZ5z558mTNjzzyiOO+Cy+8MGTPEw2KFSvm2J45c6Zme53bxRdfrNm2HT148GBQz1OoUCHN+/fv1/z1118HPVacWtu2bTXb60SLFi2qmXbigR06dEhz586d/e5z9913O7arVKmi+amnngrZWEqXLq3ZXn8ULdf8tGvXTnOlSpWCOmbChAlhGcujjz6quXHjxhEdS05jl4FwXw94kv1cEMl663X7eWDbZttrFu3nv30t5QSc+QEAAADgCUx+AAAAAHgCZW85gC1tQHBsO8Vp06Zpdpeg2VbJ9hSsbbNo2zS6jzkd8fHxmm15xdq1azUfP348S8+Rk7hXkbY/g5SUFM3BtrcOhi27crfprF+/fsieJxq4X7/232/bu+7atUtzsKVutlTu3nvv1exub43MyZs3r2P7iSee0Gzbw9rPBj4nQsfd3t2ybfRtCa8tWwvW77//rvndd9/N9PGRdvbZZwe1ny3DDGVJZsmSJTV369YtZI+bG5QrV07zN998o9mWx6alpWl+5plnHMdntfV3nz59NNtLN6yuXbtqtm3fcwLO/AAAAADwBCY/AAAAADyBsrcI+emnn/x+/ZZbbnFsu1evxz+GDx+u+bzzztOcUcmaXe3Zrpbevn37EI/uXw899JDmkSNHat6yZUvYnjO7uUsNrbfeeisbR/IP24XGlm389ttv2T6W7GBLG0ScZYC2i9WkSZM029XmN27c6Di+cOHCmt9++23NmzZt0vziiy9mYcTo0qWLY9uWWlm2hOj222/XnJveP3KC5s2ba3755Zc1lyhRwu/+tqOciLPD58KFCzXb358//vgji6PMHkWKFNFsX3MZ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iEeXM4V88lO8eHF5+eWX5eWXXw64T0xMjAwcOFAGDhwY6qcHAAAAAL9Cfs0PAAAAAOREIT/zg9CypzNtxzu7Cq9XnHXWWZptF7bVq1dn+rHs9WXuDnstW7bM9ONZGzZsyNLx0eDVV1/VfP/99zvus13BChcurPnw4cNBPbY9bf9///d/fvcJ9HWIVKlSRfP555+veeTIkX73r1mzpmPbrqlmV/imVCtrbHnmRx99FMGReNMrr7yi+a677nLcFxcX5/eYBQsW+D0mJSUlxKPL/Tp27BjpIeRa9u+hQBVV7r8ZbdMx+9pOTU0N7eByKM78AAAAAPAEJj8AAAAAPIGytxyuQoUKmr1e9lapUiXNt956q+YjR45o/vnnnx3H2FI52znsueee01y8eHHHMRl1cvNn0KBBjm27aG1utWPHDs3Lly933Ge7v7311lua7733Xs12LbBJkyY5jm/SpInmv/76S3O/fv0024Vk4dSrVy/N+fPn97tPq1atNNvfBRHn79B9990X4tF5l11k1t1hktdz1tjSZVv2abtC2veczZs3O463DZqeffbZMIzQm/r06aP5wgsvzPTxP/74YyiHk2vZv4GmT5+uuVmzZpqHDx/uOMaWN3sRZ34AAAAAeAKTHwAAAACeQNlbDvD9999rdnfEst2y8C+7KJ0tgVu4cKFjv7p162quU6dOyJ7/zTff1DxgwICQPW40evrppx3b5cqV03zbbbf5zcEaPHiw5jFjxmR+cB5UunRpzXaR0i5dumju1q2b5vXr1zuOP52fE04tMTFRs+1oKMICjoHYUqlSpUppdq8jWLFiRc221NMumv35559r7tu3r+P4NWvWZHms+C+7yGagEly3+fPna77llltCPqbcyHZus9n+XtgScnDmBwAAAIBHMPkBAAAA4AlMfgAAAAB4QozPFsVGidTU1IArMgOIrJo1a2ru2bOn5kArfH/zzTeO7SFDhmieO3eu5ih8q4qIhg0barbXwNkW1h9//LFmd6v248ePh3F0uV+bNm00P/HEE5pr1Kih+aGHHnIc4/VrfkqUKKH5lVde0Wxb9dprfvbv3+84fsGCBZrHjh3r9zm+/PLLLI4SmVW7dm3N9r38jDPOCHiMXerA/dkABCMlJUViY2Mz3IczPwAAAAA8gckPAAAAAE+g7A0AAESMXZLAlqfZP09s2/sff/zR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gKhodd23b19JSUnR27Zt2yI9JAAAAABRJqStrk/Wl+/atcuxYuuuXbu0zW1iYuJ/av+OHz8u+/btC9h+tWDBgo6WhzmZu/69Q4cOfvezrV5ff/11zUePHnXsN2/ePM22TjwtLU3zY489ptmWHIqIlChRQnNuuubHXuczc+ZMzXZFYTdbS//NN99o5hqf8JkyZYpm+1revn17wGNefvllzXZV9d9//z2kY4s2efPm1Wyv62nXrl3AY2x7/S+++EKz+z04sx566CHNvXv3dtxna/vvuusuzR999FGWnjM3ueCCCxzbtu1soOusuM4nsv7++2/N9vNbxHk9RZEiRTR7/ToVe81HRn/D2Wuo7Oe0179/oXTyOvyT7HWja9euzdJj288Z9zWoJ7nb80f679GQnvmpXLmyJCYmOi6kSk1NlaVLl+qbQ1JSkuzfv9/xRj537lxJT0+Xhg0bhnI4AAAAAKAyfebn4MGDsmnTJt3evHmzrF69WuLj46VixYrSo0cPGTRokFStWlUqV64s/fr1k3LlymlHuOrVq8u1114r9913n4wZM0bS0tKke/fucscddwTV6Q0AAAAATkemJz8rVqyQq666SrdPtm9u3769TJgwQXr37i2HDh2Szp07y/79++Wyyy6TWbNmSaFChfSYSZMmSffu3aVx48aSJ08ead26tYwcOTIE/5zIs6f/RETi4+P97jdo0CDNs2bNCuqxbRtsW0LStm1bzbl5Ank6pW5WrVq1NNvV6t2lhgid8847T/OQIUOCOuaMM87QbNu7e519b7Glbvv27XPsV7t2bc22vO3EiROZfk7b3te27betqt0r2tv9KFvxzy5BgOhg34uqVq0awZFED7t+Y548/xYa2RJCEWfpvvv9DKfPLmNw8gTESRs2bND88MMPZ/qxX3nlFc3du3f3u8+iRYs02xbYOUGmJz9XXnllhms/xMTEyMCBA2XgwIEB94mPj//P2hIAAAAAEE5R0e0NAAAAALIqpN3evKpnz56aH3zwwYD7/fXXX5p37tyZpedcsWKFZlvakpvL3mwJVfny5TN9/PDhwzV36dJF86uvvurYb/Xq1Zq//fbbTD8P/mXLG+wK9T///LPmatWqOY7ZunWr5qx2oclNbCMZ2+7fdnQUcZaXnE6pmy07/OyzzzTbn9Mdd9yheerUqZl+Dq+79957g9rPdgJFZNluZaVKlXLcZ0u1vN49tGTJkpqvvfZav/scPHjQsZ2SkqK5Zs2amm0XOATnnHPO0WzLa90VW4MHD87U41555ZWObVt6HagarE2bNpl6juzEmR8AAAAAnsDkBwAAAIAnUPYWAkWLFtVsFyJ1sws2BtvhLRB7OrlixYpZeqxoMX36dM12kUW7KGawi+Gmp6f7PV7EeUrelvQEWrAWgf3222+a77vvPs0ZdX75+uuvwzmkqGW/ly+++KLml156ybHfL7/8onnUqFGan3nmGc22c6S77NOWKuzatUuzXbzOloYi82JjYx3b9v3Iymxpilflz59fs11o/NJLL9Vsy0PdvzOHDx8+5XPYn4W7zMcuOmzL272oTp06mu3CzFaZMmUc21999ZVmW7ZrP/P79++v2b7HeZX9u/Omm27SHKiTpP3+iYi8//77p3yOSpUqaX7zzTcd9xUvXvyUx9tSbTtGEZGffvrplMeHE2d+AAAAAHgCkx8AAAAAnsDkBwAAAIAncM1PNurYsWPIHqtWrVqa4+PjQ/a40cLWWK9atUrzhRde6NjPtseePHmyZttO2d3C0a52bOtU7QrfDzzwgGbbahyBXXbZZUHtd9ttt2n+4YcfNI8fPz7kY4pWEydO1OxuB/v4449rfvTRRzU3b95cs23He8EFFziOt3X2d955p2Z3e1qcPvc1PhktHI5/xMXFabbXfIo4r3OoXr265piYGM32e3z33Xc7jv/8888122t77HUNzZo1Czg2+xnkda1btz7lPu72+GeddZbmNWvWaK5Xr57mL7/8UvNVV13lOP7333/P3CBzAXvdZ6dOnU65/6FDhxzbV1xxhd/97N+W9vfMXv8TrKpVq2p2t/d/5JFHMv14ocSZHwAAAACewOQHAAAAgCdQ9naaEhISNNvVzt1secqePXuy9Jz2FH5GLbW9ZsWKFX5zsN59913Hti37sSus29P5ttTQ3Vryzz//zPQYvKBhw4ZB7Wd/t2wLW/xr//79mt2twefOnavZlnCOGDHC72O5S67S0tI029c5ZW/Ibk2aNNFsP0sTExMDHmNbwi9evFizfZ3bdtgiIj179tTcvn17zQcOHNBctmxZzbbsWkTko48+CjgerwlU3pyamqrZvi+JiGzfvt3vMbbU0X62u9vzt2zZMtPjjDbnnHOOYzujvzv9CfT+n5FAZaMZWbt2reYhQ4ZotqWlOQFnfgAAAAB4ApMfAAAAAJ5A7dRpKlKkiGbbXcbNngI8cuRIlp7TnuYMtPL3ypUrHduUqmReSkqK5vvuu0/zmWeeqblRo0aa3V38hg8fHsbRRa9PPvlE8+WXXx7UMT///HO4hpNr2U5ittuhLVtYtGiR5qNHjzqOb9WqleZLL71Us+1w+Nlnn2k+ceJEFkcMy65eb8uuvMJ+ntpSN1t2Zr9HIiLdunXTbFeVD6Rw4cKObbva/Q033KC5ZMmSmpOTkzV37dr1lM/hJTVr1tQc6O8h25UyUJmbm/0sHjNmjOaBAwc69hs1apRm+1rITc4//3zHtu0++/fff2ueMWOG5oULF2o+++yzHce3bdtWc+nSpf0+Z548/54fcXeo/OKLLzT36NFD86+//ur3sXIazvwAAAAA8AQmPwAAAAA8gbK3KOJeJOqk48ePa3Z3Lstqhzmvs6fdAy1m2qVLF8c2ZW+IJLswYLt27TTbBetsmYjbxRdfrLlPnz6abUer9evXa77nnnscxy9btixzA/YIWypry0lEnCUlP/74o2b7/uMVLVq00Gy7utlFHQcMGOA4xr2Aoz+21M3dKSvQAqa2VNSWGZ177rmO/dxleF5ju3IG6tC5YcOGLD2HXZTTXbaYlJSUpceORva1ad9z27RpE9Txtvtev379/O5j35dsR0QRkWnTpmmOxkVmOfMDAAAAwBOY/AAAAADwBMrecoGNGzdqHjlyZARH4k3uTilXXXWV5nnz5mX3cHIs2yHspZdeCrifPR3PgrGnZjtPioi89tprmu2CpbNnzw7q8b777jvNN910k2ZbdmI797kXHLzmmms025+l111wwQWa3Z2Tgl1A0Mt++OEHzRmVudmSqGrVqmm2pT22o6GIyOHDhzU/8sgjmletWqX5ww8/1NyrVy/H8ffff3+GY4fI0qVLM33MRRddpPmSSy4J5XCiji01FnF2vNuyZcspj+/QoYNjO5iueLaLm+22J+L8bIlGnPkBAAAA4AlMfgAAAAB4ApMfAAAAAJ7ANT+nydY72usS3Nd/lClTRnO+fP9+u217asvdAtXWEjdo0MDvMU8++WQQI0a4FC1a1LF91llnRWYgOdwff/wR1H72d8u2bf7pp59CPaRcwd1219bGDxo0SPPptOO116LMnz9f83333afZtsAWEWndurXm8ePHZ/o5AX/s6/qMM85w3HfddddpLlu2rObatWtrtq/llStXOo637drXrl3r9/nt+5d9/Ys4lzf47bff/P8DcjF7zZTN9vor+/fL2LFjAz5W8eLFNQ8dOlRzyZIlAx7z2GOPBT/YKLVu3boMt/25+eabNT/33HOO++Lj4/0es3z5cs3u6zlzE878AAAAAPAEJj8AAAAAPIGyt9O0fft2zba17DPPPOPYz56OffnllzUnJyf7fdy77rrLsR3Macdg2hxGi/Llyzu2d+7cqTlc7WDdpYoFChTQ3K5dO822BMvas2ePY3vhwoWhG5wH2fKG66+/XvP7778fieHkeH379g143+jRo8PynEePHg14H2Wf/tlW1xmx7ZW9aNGiRZpjYmI02xLwjD4L7GfG22+/rdmWZ86YMSPT41q8eLHmunXrOu679NJLNXux7G3Dhg2a16xZo9m2qq5Ro0ZQjzVs2DDNdtkIa8GCBY5tW5KLf02ZMkVzRr8ztjy5e/fuYR1TTsGZHwAAAACewOQHAAAAgCdQ9paN3nrrLc0dO3bUfPvtt2sePHhwwOOPHTum2a7u6175N5rZckIRkbvvvlvzpEmTNJ9OCVzBggU19+7dW3PXrl0d+yUkJJzysU6cOKHZ3dFq48aNmR4b/KtZs6bmQoUKaT5y5EgkhpMj1a9f37Ftu/X89ddfYXnOF154IeB9uakMN5QaNWqk2d3VMz093W8eMWKEZltq9cADDziOP51OfjnVsmXLNNsOb5b7NW9LzWx5WkpKSsjGZX+X3J8/559/vuZ33nknZM8ZjSZPnqzZlr1Vq1ZNs7u8/dprr9VsP48Dfc7/+OOPju1A3XO9wnb8HDdunGZbNuq2detWzbYTXEYlzbkJZ34AAAAAeAKTHwAAAACeQNlbNmrWrJlmW8J1xRVXaM6bN2/A420JhF38Kzdxn3KdOHGi5osvvlizXQjz+eef11ylShXH8XaRr7PPPluz7SIWLLt4m+3Cl1G3LfzLlvPYjkzlypULeIxdJDij3w0v++yzzxzbtmwoq+WBdjHJF198UXPVqlU1uxeMdC966mVJSUma7ffS/i6IOMt73IsRnmQ7ieamMjc3W1L83Xff+d0n0NfDqUWLFgHvC7aTmRdMmDBBs12A3b7+3aXh+fPn1xyo1G3u3Lmae/bsmdVh5ir2M/Syyy7TbL+X7u+rLdf/9ddfwzi6nIkzPwAAAAA8gckPAAAAAE+g7C0EbOejWrVqOe679dZb/R4TaPEut23btmm2XVRyK/f3xZ42d3dlO+mhhx4K6Rjs6eHff/9ds+1Is2nTppA+pxfYzjPFixcP6ph58+ZpPnToUMjHlBu433OsadOmabZlmxl58MEHNdsF72ypm+225C4HSk1NDep5vODMM8/UXLhw4aCOsR0vbXnXs88+G7qBIdPmzJmjuU6dOo77bEmW1+3bt09zy5YtNdv3ctu5MyP275+HH35Ysy2N9KpSpUppHj58+Cn3d5cnjxo1KuRjiiac+QEAAADgCUx+AAAAAHgCkx8AAAAAnhDjC9RXMAdLTU2VuLi4SA/Dr/j4eMe2bdV83XXXnfL4l19+2bFtr/NZunRp1gYXhewK3/Z6INteOtha+kBef/11x/aSJUs0258fssauav/ee+9pDnRdnIjIBx98oLlt27bhGViUu/LKKx3b9vqDPXv2aH7//ff9Hm9XBxdxtuS3XnvtNc32+pM///wz6LF6TZEiRTTb17L7Oim7KvtTTz2lee/evWEcHZB97Pu8+zM3NjZW86JFizR36dJF8/r168M4uugzYMAAzf369fO7j73O07bAFhH54YcfwjOwHCAlJcXxmvKHMz8AAAAAPIHJDwAAAABPoOwNQLarVKmS5t69ezvuq1mzpuY+ffpojsSq7tHAro4uItKqVSvNTZs21dy8eXPN5cuX1+xebf3jjz/W/Omnn2petmxZlscKAMi6ihUran7ppZc02/f/1q1ba/7ss8+yZ2A5AGVvAAAAAPA/TH4AAAAAeAJlbwAAAACiHmVvAAAAAPA/TH4AAAAAeAKTHwAAAACewOQHAAAAgCcw+QEAAADgCUx+AAAAAHhCpic/CxYskJYtW0q5cuUkJibGsQJ4WlqaPP7441K7dm0pWrSolCtXTtq1ayc7d+50PMa+ffukbdu2EhsbKyVKlJBOnTrJwYMHs/yPAQAAAIBAMj35OXTokNStW1dGjRr1n/v+/vtvWbVqlfTr109WrVoln3zyiWzYsEFuuOEGx35t27aVdevWyezZs2XGjBmyYMEC6dy58+n/KwAAAADgVHxZICK+qVOnZrjPsmXLfCLi27Jli8/n8/nWr1/vExHf8uXLdZ+ZM2f6YmJifDt27AjqeVNSUnwiwo0bN27cuHHjxo0bN24+EfGlpKScch4R9mt+UlJSJCYmRkqUKCEiIkuWLJESJUpIgwYNdJ8mTZpInjx5ZOnSpX4f4+jRo5Kamuq4AQAAAEBmhHXyc+TIEXn88celTZs2EhsbKyIiycnJUqZMGcd++fLlk/j4eElOTvb7OEOHDpW4uDi9VahQIZzDBgAAAJALhW3yk5aWJrfddpv4fD4ZPXp0lh6rb9++kpKSordt27aFaJQAAAAAvCJfOB705MRny5YtMnfuXD3rIyKSmJgou3fvdux//Phx2bdvnyQmJvp9vIIFC0rBggXDMVQAAAAAHhHyMz8nJz4bN26Ur7/+WkqWLOm4PykpSfbv3y8rV67Ur82dO1fS09OlYcOGoR4OAAAAAIjIaZz5OXjwoGzatEm3N2/eLKtXr5b4+HgpW7as3HLLLbJq1SqZMWOGnDhxQq/jiY+PlwIFCkj16tXl2muvlfvuu0/GjBkjaWlp0r17d7njjjukXLlyQY3hn0ZzAAAAAPCPoOYIQfWWNubNm+e3tVz79u19mzdvDth6bt68efoYe/fu9bVp08ZXrFgxX2xsrK9jx46+AwcOBD2Gbdu2RbyVHjdu3Lhx48aNGzdu3HLObdu2baecR8T4ovA0Snp6uuzcuVN8Pp9UrFhRtm3b5riuCMgOqampUqFCBV5/iAhef4gkXn+IJF5/cPP5fHLgwAEpV66c5MmT8VU9YWl4EG558uSRM888U9f7iY2N5cWPiOH1h0ji9YdI4vWHSOL1BysuLi6o/cK+yCkAAAAA5ARMfgAAAAB4QlRPfgoWLCgDBgxgDSBEBK8/RBKvP0QSrz9EEq8/ZEVUNjwAAAAAgMyK6jM/AAAAABAsJj8AAAAAPIHJDwAAAABPYPIDAAAAwBOidvIzatQoOeuss6RQoULSsGFDWbZsWaSHhFzo6aeflpiYGMetWrVqev+RI0ekW7duUrJkSSlWrJi0bt1adu3aFcERI5otWLBAWrZsKeXKlZOYmBj59NNPHff7fD7p37+/lC1bVgoXLixNmjSRjRs3OvbZt2+ftG3bVmJjY6VEiRLSqVMnOXjwYDb+KxCtTvX669Chw3/eD6+99lrHPrz+cLqGDh0qF154oRQvXlzKlCkjN954o2zYsMGxTzCfuVu3bpUWLVpIkSJFpEyZMvLYY4/J8ePHs/OfghwuKic/H374ofTq1UsGDBggq1atkrp160qzZs1k9+7dkR4acqGaNWvKH3/8obeFCxfqfT179pTp06fLlClTZP78+bJz5065+eabIzhaRLNDhw5J3bp1ZdSoUX7vHz58uIwcOVLGjBkjS5culaJFi0qzZs3kyJEjuk/btm1l3bp1Mnv2bJkxY4YsWLBAOnfunF3/BESxU73+RESuvfZax/vh+++/77if1x9O1/z586Vbt27y3XffyezZsyUtLU2aNm0qhw4d0n1O9Zl74sQJadGihRw7dkwWL14sEydOlAkTJkj//v0j8U9CTuWLQhdddJGvW7duun3ixAlfuXLlfEOHDo3gqJAbDRgwwFe3bl2/9+3fv9+XP39+35QpU/RrP/30k09EfEuWLMmmESK3EhHf1KlTdTs9Pd2XmJjoe/755/Vr+/fv9xUsWND3/vvv+3w+n2/9+vU+EfEtX75c95k5c6YvJibGt2PHjmwbO6Kf+/Xn8/l87du397Vq1SrgMbz+EEq7d+/2iYhv/vz5Pp8vuM/cL774wpcnTx5fcnKy7jN69GhfbGys7+jRo9n7D0COFXVnfo4dOyYrV66UJk2a6Nfy5MkjTZo0kSVLlkRwZMitNm7cKOXKlZOzzz5b2rZtK1u3bhURkZUrV0paWprjtVitWjWpWLEir0WE3ObNmyU5OdnxeouLi5OGDRvq623JkiVSokQJadCgge7TpEkTyZMnjyxdujTbx4zc55tvvpEyZcrIeeedJ127dpW9e/fqfbz+EEopKSkiIhIfHy8iwX3mLlmyRGrXri0JCQm6T7NmzSQ1NVXWrVuXjaNHThZ1k589e/bIiRMnHC9sEZGEhARJTk6O0KiQWzVs2FAmTJggs2bNktGjR8vmzZvl8ssvlwMHDkhycrIUKFBASpQo4TiG1yLC4eRrKqP3vuTkZClTpozj/nz58kl8fDyvSWTZtddeK2+//bbMmTNHhg0bJvPnz5fmzZvLiRMnRITXH0InPT1devToIZdeeqnUqlVLRCSoz9zk5GS/75En7wNERPJFegBATta8eXPNderUkYYNG0qlSpVk8uTJUrhw4QiODACy1x133KG5du3aUqdOHalSpYp888030rhx4wiODLlNt27dZO3atY5rbIFQibozP6VKlZK8efP+p7vHrl27JDExMUKjgleUKFFCzj33XNm0aZMkJibKsWPHZP/+/Y59eC0iHE6+pjJ670tMTPxP45fjx4/Lvn37eE0i5M4++2wpVaqUbNq0SUR4/SE0unfvLjNmzJB58+bJmWeeqV8P5jM3MTHR73vkyfsAkSic/BQoUEDq168vc+bM0a+lp6fLnDlzJCkpKYIjgxccPHhQfv31VylbtqzUr19f8ufP73gtbtiwQbZu3cprESFXuXJlSUxMdLzeUlNTZenSpfp6S0pKkv3798vKlSt1n7lz50p6ero0bNgw28eM3G379u2yd+9eKVu2rIjw+kPW+Hw+6d69u0ydOlXmzp0rlStXdtwfzGduUlKSrFmzxjEJnz17tsTGxkqNGjWy5x+CnC/SHRdOxwcffOArWLCgb8KECb7169f7Onfu7CtRooSjuwcQCo888ojvm2++8W3evNm3aNEiX5MmTXylSpXy7d692+fz+Xz333+/r2LFir65c+f6VqxY4UtKSvIlJSVFeNSIVgcOHPB9//33vu+//94nIr4XX3zR9/333/u2bNni8/l8vueee85XokQJ32effeb78ccffa1atfJVrlzZd/jwYX2Ma6+91nf++ef7li5d6lu4cKGvatWqvjZt2kTqn4QoktHr78CBA75HH33Ut2TJEt/mzZt9X3/9te+CCy7wVa1a1XfkyBF9DF5/OF1du3b1xcXF+b755hvfH3/8obe///5b9znVZ+7x48d9tWrV8jVt2tS3evVq36xZs3ylS5f29e3bNxL/JORQUTn58fl8vldffdVXsWJFX4ECBXwXXXSR77vvvov0kJAL3X777b6yZcv6ChQo4Ctfvrzv9ttv923atEnvP3z4sO+BBx7wnXHGGb4iRYr4brrpJt8ff/wRwREjms2bN88nIv+5tW/f3ufz/dPuul+/fr6EhARfwYIFfY0bN/Zt2LDB8Rh79+71tWnTxlesWDFfbGysr2PHjr4DBw5E4F+DaJPR6+/vv//2NW3a1Fe6dGlf/vz5fZUqVfLdd999//lPR15/OF3+Xnsi4hs/frzuE8xn7u+//+5r3ry5r3Dhwr5SpUr5HnnkEV9aWlo2/2uQk8X4fD5fdp9tAgAAAIDsFnXX/AAAAADA6WDyAwAAAMATmPwAAAAA8AQmPwAAAAA8gckPAAAAAE9g8gMAAADAE5j8AAAAAPAEJj8AAAAAPIHJDwAAAABPYPIDAAAAwBOY/AAAAADwBCY/AAAAADzh/wHLhoQ6QyjhygAAAABJRU5ErkJggg==",
      "text/plain": [
       "<Figure size 1000x1000 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "inputs = next(iter(train_loader))[0]\n",
    "input_grid = utils.make_grid(inputs)\n",
    "\n",
    "fig = plt.figure(figsize=(10, 10))\n",
    "inp = input_grid.numpy().transpose((1, 2, 0))\n",
    "plt.imshow(inp)\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [],
   "source": [
    "def create_convolutional_network():\n",
    "    \"\"\"\n",
    "    This function returns the convolutional network layed out above.\n",
    "    \"\"\"\n",
    "    return nn.Sequential(\n",
    "        nn.Conv2d(in_channels=1, out_channels=16, kernel_size=3, padding=1),\n",
    "        nn.ReLU(),\n",
    "        nn.MaxPool2d(2),\n",
    "        nn.Conv2d(in_channels=16, out_channels=32, kernel_size=3, padding=1),\n",
    "        nn.ReLU(),\n",
    "        nn.MaxPool2d(2),\n",
    "        nn.Dropout(0.25),\n",
    "        nn.Flatten(),\n",
    "        nn.Linear(32*7*7, 128),\n",
    "        nn.ReLU(),\n",
    "        nn.Dropout(0.5),\n",
    "        nn.Linear(128, num_classes)\n",
    "    )"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [],
   "source": [
    "def poutyne_train(pytorch_network):\n",
    "    \"\"\"\n",
    "    This function creates a Poutyne Model (see https://poutyne.org/model.html), sends the\n",
    "    Model on the specified device, and uses the `fit_generator` method to train the\n",
    "    neural network. At the end, the `evaluate_generator` is used on  the test set.\n",
    "\n",
    "    Args:\n",
    "        pytorch_network (torch.nn.Module): The neural network to train.\n",
    "    \"\"\"\n",
    "    print(pytorch_network)\n",
    "\n",
    "    optimizer = optim.SGD(pytorch_network.parameters(), lr=learning_rate)\n",
    "    loss_function = nn.CrossEntropyLoss()\n",
    "\n",
    "    # Poutyne Model\n",
    "    model = Model(pytorch_network, optimizer, loss_function, batch_metrics=['accuracy'])\n",
    "\n",
    "    # Send model on GPU\n",
    "    model.to(device)\n",
    "\n",
    "    # Train\n",
    "    model.fit_generator(train_loader, valid_loader, epochs=num_epochs)\n",
    "\n",
    "    # Test\n",
    "    test_loss, test_acc = model.evaluate_generator(test_loader)\n",
    "    print('Test:\\n\\tLoss: {}\\n\\tAccuracy: {}'.format(test_loss, test_acc))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Sequential(\n",
      "  (0): Conv2d(1, 16, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))\n",
      "  (1): ReLU()\n",
      "  (2): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)\n",
      "  (3): Conv2d(16, 32, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))\n",
      "  (4): ReLU()\n",
      "  (5): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)\n",
      "  (6): Dropout(p=0.25, inplace=False)\n",
      "  (7): Flatten(start_dim=1, end_dim=-1)\n",
      "  (8): Linear(in_features=1568, out_features=128, bias=True)\n",
      "  (9): ReLU()\n",
      "  (10): Dropout(p=0.5, inplace=False)\n",
      "  (11): Linear(in_features=128, out_features=10, bias=True)\n",
      ")\n",
      "\u001b[35mEpoch: \u001b[36m1/1 \u001b[35mTrain steps: \u001b[36m1500 \u001b[35mVal steps: \u001b[36m375 \u001b[32m19.20s \u001b[35mloss:\u001b[94m 0.396201\u001b[35m acc:\u001b[94m 87.187500\u001b[35m val_loss:\u001b[94m 0.087136\u001b[35m val_acc:\u001b[94m 97.375000\u001b[0m\n",
      "\u001b[35mTest steps: \u001b[36m313 \u001b[32m2.45s \u001b[35mtest_loss:\u001b[94m 0.074455\u001b[35m test_acc:\u001b[94m 97.590000\u001b[0m                                                   \n",
      "Test:\n",
      "\tLoss: 0.07445458313710987\n",
      "\tAccuracy: 97.59\n"
     ]
    }
   ],
   "source": [
    "conv_net = create_convolutional_network()\n",
    "poutyne_train(conv_net)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (Local)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.10.13"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
